#include "UndoRedoManager.h"
#include <QDebug>
#include <QCoreApplication>
#include <QDir>

// UndoRedoManager实现
UndoRedoManager::UndoRedoManager(QObject *parent) 
    : QObject(parent), 
      m_maxHistorySize(50),  // 默认最大历史记录数量
      m_isHistoryPaused(false)
{
    // 初始化时创建临时目录并存储路径
    m_tempDirectoryPath = createTempDirectory();
}

QUndoStack* UndoRedoManager::getOrCreateUndoStack(const QString& imageGuid)
{
    if (imageGuid.isEmpty()) {
        // 不允许空的imageGuid
        return nullptr;
    }
    
    if (!m_undoStacks.contains(imageGuid)) {
        // 创建新的撤销栈
        QUndoStack* stack = new QUndoStack(this);
        
        // 设置撤销限制
        stack->setUndoLimit(m_maxHistorySize);
        
        // 添加到映射中
        m_undoStacks[imageGuid] = stack;
    }
    
    return m_undoStacks[imageGuid];
}

UndoRedoManager::~UndoRedoManager()
{
    // 清理资源
    clearHistory();
    
    // 清理所有图像特定的撤销栈
    qDeleteAll(m_undoStacks);
    m_undoStacks.clear();
}

void UndoRedoManager::addOperation(const OperationInfo& operationInfo)
{
    if (m_isHistoryPaused) {
        return;
    }
    
    // 不允许空的imageGuid
    if (operationInfo.imageGuid.isEmpty()) {
        return;
    }
    
    // 获取或创建指定图像的撤销栈
    QUndoStack* stack = getOrCreateUndoStack(operationInfo.imageGuid);
    
    // 如果stack为空，表示图像GUID无效
    if (!stack) {
        return;
    }
    
    // 使用已经创建好的临时目录路径
    
    // 创建ImageOperation对象，直接传递临时目录路径
    ImageOperation* operation = new ImageOperation(
        operationInfo.imageGuid,
        operationInfo.type,
        operationInfo.previousValue,
        operationInfo.newValue,
        operationInfo.undoFunc,
        operationInfo.redoFunc,
        operationInfo.description,
        m_tempDirectoryPath
    );
    
    // 使用QUndoStack添加操作
    stack->push(operation);
    
    // 确保历史记录不超过最大限制
    if (stack->count() > m_maxHistorySize) {
        stack->setUndoLimit(m_maxHistorySize);
    }
    
    // 发出操作添加信号
    emit operationAdded(operation);
    
    // 发出状态变化信号
    emit undoRedoStateChanged(operationInfo.imageGuid, stack->canUndo(), stack->canRedo());
}

/**
 * @brief 撤销指定图像的上一步操作
 * @param imageGuid 图像GUID
 * @return 是否撤销成功
 */
bool UndoRedoManager::undo(const QString& imageGuid, ImageOperationType* operationType, QString* operationDescription)
{
    QUndoStack* stack = getOrCreateUndoStack(imageGuid);
    
    if (!stack->canUndo()) {
        return false;
    }
    
    // 获取当前要撤销的命令
    const QUndoCommand *command = nullptr;
    if (stack->index() > 0) {
        command = stack->command(stack->index() - 1);
        
        // 尝试将命令转换为ImageOperation类型
        const ImageOperation* imageOp = dynamic_cast<const ImageOperation*>(command);
        if (imageOp) {
            // 如果提供了输出参数，返回操作类型和描述
            if (operationType) {
                *operationType = imageOp->getType();
            }
            if (operationDescription) {
                *operationDescription = imageOp->text();
            }
        }
    }
    
    // 执行撤销
    stack->undo();
    
    // 发出撤销信号
    if (command) {
        emit operationUndone(const_cast<QUndoCommand*>(command));
    }
    
    // 发出状态变化信号
    emit undoRedoStateChanged(imageGuid, stack->canUndo(), stack->canRedo());
    
    return true;
}

/**
 * @brief 重做指定图像的上一步撤销操作
 * @param imageGuid 图像GUID
 * @return 是否重做成功
 */
bool UndoRedoManager::redo(const QString& imageGuid, ImageOperationType* operationType, QString* operationDescription)
{
    QUndoStack* stack = getOrCreateUndoStack(imageGuid);
    
    if (!stack->canRedo()) {
        return false;
    }
    
    // 获取当前要重做的命令
    const QUndoCommand *command = nullptr;
    if (stack->index() < stack->count()) {
        command = stack->command(stack->index());
        
        // 尝试将命令转换为ImageOperation类型
        const ImageOperation* imageOp = dynamic_cast<const ImageOperation*>(command);
        if (imageOp) {
            // 如果提供了输出参数，返回操作类型和描述
            if (operationType) {
                *operationType = imageOp->getType();
            }
            if (operationDescription) {
                *operationDescription = imageOp->text();
            }
        }
    }
    
    // 执行重做
    stack->redo();
    
    // 发出重做信号
    if (command) {
        emit operationRedone(const_cast<QUndoCommand*>(command));
    }
    
    // 发出状态变化信号
    emit undoRedoStateChanged(imageGuid, stack->canUndo(), stack->canRedo());
    
    return true;
}

void UndoRedoManager::clearHistory()
{
    // 清理所有图像特定的撤销栈
    QList<QString> imageGuids = m_undoStacks.keys();
    for (const auto& guid : imageGuids) {
        m_undoStacks[guid]->clear();
        emit undoRedoStateChanged(guid, false, false);
    }
    
    emit historyCleared();
}

/**
 * @brief 清空指定图像的撤销和重做历史
 * @param imageGuid 图像GUID
 */
void UndoRedoManager::clearHistory(const QString& imageGuid)
{
    if (imageGuid.isEmpty()) {
        // 不允许空的imageGuid
        return;
    }
    
    if (m_undoStacks.contains(imageGuid)) {
        m_undoStacks[imageGuid]->clear();
        emit undoRedoStateChanged(imageGuid, false, false);
    }
}

/**
 * @brief 检查是否可以对指定图像执行撤销操作
 * @param imageGuid 图像GUID
 * @return 是否可以撤销
 */
bool UndoRedoManager::canUndo(const QString& imageGuid) const
{
    if (imageGuid.isEmpty()) {
        // 不允许空的imageGuid
        return false;
    }
    
    if (m_undoStacks.contains(imageGuid)) {
        return m_undoStacks[imageGuid]->canUndo();
    }
    
    return false;
}

/**
 * @brief 检查是否可以对指定图像执行重做操作
 * @param imageGuid 图像GUID
 * @return 是否可以重做
 */
bool UndoRedoManager::canRedo(const QString& imageGuid) const
{
    if (imageGuid.isEmpty()) {
        // 不允许空的imageGuid
        return false;
    }
    
    if (m_undoStacks.contains(imageGuid)) {
        return m_undoStacks[imageGuid]->canRedo();
    }
    
    return false;
}

/**
 * @brief 获取指定图像当前可以撤销的操作描述
 * @param imageGuid 图像GUID
 * @return 操作描述字符串，如果没有可撤销操作则返回空字符串
 */
QString UndoRedoManager::getUndoDescription(const QString& imageGuid) const
{
    if (imageGuid.isEmpty()) {
        // 不允许空的imageGuid
        return QString();
    }
    
    if (m_undoStacks.contains(imageGuid)) {
        return m_undoStacks[imageGuid]->undoText();
    }
    
    return QString();
}

/**
 * @brief 获取指定图像当前可以重做的操作描述
 * @param imageGuid 图像GUID
 * @return 操作描述字符串，如果没有可重做操作则返回空字符串
 */
QString UndoRedoManager::getRedoDescription(const QString& imageGuid) const
{
    if (imageGuid.isEmpty()) {
        // 不允许空的imageGuid
        return QString();
    }
    
    if (m_undoStacks.contains(imageGuid)) {
        return m_undoStacks[imageGuid]->redoText();
    }
    
    return QString();
}

void UndoRedoManager::setMaxHistorySize(int maxSize)
{
    if (maxSize > 0) {
        m_maxHistorySize = maxSize;
        
        // 设置所有图像特定撤销栈的限制
        for (const auto& guid : m_undoStacks.keys()) {
            m_undoStacks[guid]->setUndoLimit(maxSize);
            emit undoRedoStateChanged(guid, m_undoStacks[guid]->canUndo(), m_undoStacks[guid]->canRedo());
        }
    }
}

QVariant UndoRedoManager::getCurrentOperationValue(const QString& imageGuid) const
{
    if (imageGuid.isEmpty()) {
        return QVariant(); // 无效的QVariant，表示没有可执行的操作
    }
    
    if (!m_undoStacks.contains(imageGuid)) {
        return QVariant();
    }
    
    QUndoStack* stack = m_undoStacks[imageGuid];
    
    // 首先检查是否有可撤销的操作
    if (stack->canUndo()) {
        // 获取栈顶的撤销命令
        const QUndoCommand* command = stack->command(stack->index() - 1);
        if (command) {
            // 尝试转换为ImageOperation类型
            const ImageOperation* imageOperation = dynamic_cast<const ImageOperation*>(command);
            if (imageOperation) {
                // 返回操作前的值作为撤销操作的值
                return imageOperation->getPreviousValue();
            }
        }
    }
    
    // 然后检查是否有可重做的操作
    if (stack->canRedo()) {
        // 获取栈顶的重做命令
        const QUndoCommand* command = stack->command(stack->index());
        if (command) {
            // 尝试转换为ImageOperation类型
            const ImageOperation* imageOperation = dynamic_cast<const ImageOperation*>(command);
            if (imageOperation) {
                // 返回操作后的值作为重做操作的值
                return imageOperation->getNewValue();
            }
        }
    }
    
    return QVariant(); // 无效的QVariant，表示没有可执行的操作
}

int UndoRedoManager::getMaxHistorySize() const
{
    return m_maxHistorySize;
}

/**
 * @brief 获取指定图像的撤销栈大小
 * @param imageGuid 图像GUID
 * @return 撤销栈中的操作数量
 */
int UndoRedoManager::getUndoStackSize(const QString& imageGuid) const
{
    if (imageGuid.isEmpty()) {
        // 不允许空的imageGuid
        return 0;
    }
    
    if (m_undoStacks.contains(imageGuid)) {
        return m_undoStacks[imageGuid]->count();
    }
    
    return 0;
}

/**
 * @brief 创建临时目录
 * 确保软件运行目录下的temp文件夹存在
 * @return 临时目录路径，如果创建失败则返回空字符串
 */
QString UndoRedoManager::createTempDirectory()
{
    // 获取应用程序运行目录
    QString appDir = QCoreApplication::applicationDirPath();
    
    // 构建temp目录路径
    QString tempDirPath = appDir + QDir::separator() + "temp";
    
    // 创建QDir对象
    QDir tempDir(tempDirPath);
    
    // 如果目录不存在，则创建它
    if (!tempDir.exists()) {
        // 创建目录，如果创建失败则返回空字符串
        if (!tempDir.mkpath(".")) {
            qWarning() << "无法创建临时目录: " << tempDirPath;
            return QString();
        }
        qDebug() << "创建临时目录成功: " << tempDirPath;
    }
    
    return tempDirPath;
}

void UndoRedoManager::pauseHistory()
{
    m_isHistoryPaused = true;
    // 不再依赖默认撤销栈，此方法会影响所有图像的撤销栈操作记录
}

void UndoRedoManager::resumeHistory()
{
    m_isHistoryPaused = false;
    // 不再依赖默认撤销栈，此方法会影响所有图像的撤销栈操作记录
}

bool UndoRedoManager::isHistoryPaused() const
{
    return m_isHistoryPaused;
}

void UndoRedoManager::addCompositeOperation(
        const QList<OperationInfo>& operationsInfo,
        const QString& description)
{
    if (operationsInfo.isEmpty() || m_isHistoryPaused) {
        return;
    }
    
    // 检查所有操作是否属于同一个图像
    QString imageGuid;
    bool sameImage = true;
    
    for (const auto& info : operationsInfo) {
        if (imageGuid.isEmpty()) {
            imageGuid = info.imageGuid;
            if (imageGuid.isEmpty()) {
                // 不允许空的imageGuid
                return;
            }
        } else if (info.imageGuid != imageGuid) {
            sameImage = false;
            break;
        }
    }
    
    // 所有操作必须属于同一个图像
    if (!sameImage) {
        return;
    }
    
    // 创建一个父命令，用于将多个操作合并为一个撤销/重做单元
    QUndoCommand* parentCommand = new QUndoCommand(description);
    
    // 遍历所有操作信息，为每个信息创建一个新的ImageOperation对象
    // 并在构造函数中设置父命令，这样就能正确建立父子关系
    for (const auto& info : operationsInfo) {
        // 使用已经创建好的临时目录路径
        
        // 创建ImageOperation对象，直接传递临时目录路径
        new ImageOperation(
            info.imageGuid,
            info.type,
            info.previousValue,
            info.newValue,
            info.undoFunc,
            info.redoFunc,
            info.description,
            m_tempDirectoryPath,
            parentCommand
        );
    }
    
    // 获取图像的撤销栈
    QUndoStack* stack = getOrCreateUndoStack(imageGuid);
    if (!stack) {
        // 图像GUID无效
        delete parentCommand;
        return;
    }
    
    // 将父命令添加到撤销栈，这样所有子命令也会被添加
    stack->push(parentCommand);
    
    // 确保历史记录不超过最大限制
    if (stack->count() > m_maxHistorySize) {
        stack->setUndoLimit(m_maxHistorySize);
    }
    
    // 发出操作添加信号
    emit operationAdded(parentCommand);
    
    // 发出状态变化信号
    emit undoRedoStateChanged(imageGuid, stack->canUndo(), stack->canRedo());
}
